package com.soup.common.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.HibernateValidator;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.sql.DataSource;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 应用配置类入口
 *
 * @author zhaoyi
 */
@Slf4j
@Configuration
public class AppConfiguration {

    /**
     * 线程池配置
     *
     * @return 配置中的线程池配置对象
     */
    @Bean
    @ConfigurationProperties(prefix = ThreadPoolProperties.THREAD_POOL_CONF_PREFIX, ignoreInvalidFields = true)
    public ThreadPoolProperties buidThreadPoolConfig() {
        return new ThreadPoolProperties();
    }

    /**
     * 构建的异步线程池的方法
     * @return Executor
     */
    @Bean(name = "asyncTask")
    public Executor getExecutor() {
        ThreadPoolProperties poolConfig = buidThreadPoolConfig();

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(poolConfig.getCoreSize());
        executor.setMaxPoolSize(poolConfig.getMaxSize());
        executor.setQueueCapacity(poolConfig.getQueueCapacity());
        executor.setKeepAliveSeconds(poolConfig.getKeepAliveSeconds());
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setThreadNamePrefix("app-async-thread-");

        return executor;
    }

    /**
     * jwt相关配置
     */
    @Bean
    @ConfigurationProperties(prefix = JwtProperties.JWT_PREFIX, ignoreInvalidFields = true)
    public JwtProperties buildJwtProperties() {
        return new JwtProperties();
    }

    /**
     * 文件相关配置属性
     */
    @Bean
    @ConfigurationProperties(prefix = FileProperties.FILE_CONFIG_PREFIX, ignoreInvalidFields = true)
    public FileProperties buildFileProperties() {
        return new FileProperties();
    }

    /**
     * 上传文件的配置
     * @return MultipartConfigElement 配置类
     */
    @Bean(name = "multipartResolver")
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding(StandardCharsets.UTF_8.displayName());

        FileProperties fileProperties = buildFileProperties();
        multipartResolver.setMaxUploadSize(fileProperties.getMaxUploadSize());
        multipartResolver.setMaxUploadSizePerFile(fileProperties.getMaxUploadSizePerFile());
        return multipartResolver;
    }

    /**
     * 数据库配置参数
     */
    @Bean
    @ConfigurationProperties(prefix = DbProperties.DB_CONFIG_PREFIX, ignoreInvalidFields = true)
    public DbProperties buidDbProperties() {
        return new DbProperties();
    }

    /**
     * 数据源 DataSource，配置DruidDataSource数据源
     *
     * @return DruidDataSource数据源
     */
    @Bean
    @Primary
    public DataSource dataSource() {
        DbProperties dbProperties = buidDbProperties();

        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(dbProperties.getUrl());
        datasource.setUsername(dbProperties.getUsername());
        datasource.setPassword(dbProperties.getPassword());
        datasource.setDriverClassName(dbProperties.getDriverClassName());
        datasource.setInitialSize(dbProperties.getInitialSize());
        datasource.setMinIdle(dbProperties.getMinIdle());
        datasource.setMaxActive(dbProperties.getMaxActive());
        datasource.setMaxWait(dbProperties.getMaxWait());
        datasource.setTimeBetweenEvictionRunsMillis(dbProperties.getTimeBetweenEvictionRunsMillis());
        datasource.setMinEvictableIdleTimeMillis(dbProperties.getMinEvictableIdleTimeMillis());
        datasource.setValidationQuery(dbProperties.getValidationQuery());
        datasource.setTestWhileIdle(dbProperties.getTestWhileIdle());
        datasource.setTestOnBorrow(dbProperties.getTestOnBorrow());
        datasource.setTestOnReturn(dbProperties.getTestOnReturn());
        datasource.setPoolPreparedStatements(dbProperties.getPoolPreparedStatements());
        datasource.setMaxOpenPreparedStatements(dbProperties.getMaxOpenPreparedStatements());
        datasource.setMaxPoolPreparedStatementPerConnectionSize(
                dbProperties.getMaxPoolPreparedStatementPerConnectionSize());
        datasource.setConnectionProperties(dbProperties.getConnectionProperties()
                .replace("${publicKey}", dbProperties.getPublicKey()));
        try {
            datasource.setFilters(dbProperties.getFilters());
        } catch (SQLException e) {
            log.error("druid configuration initialization filter", e);
        }

        return datasource;
    }

    /**
     * Kaptcha配置
     * @return DefaultKaptcha
     */
    @Bean
    public DefaultKaptcha getDefaultKaptcha() {
        Properties properties = new Properties();
        properties.setProperty("kaptcha.border", "yes");
        properties.setProperty("kaptcha.border.color", "105,179,90");
        properties.setProperty("kaptcha.noise.color", "216,216,216");
        properties.setProperty("kaptcha.textproducer.font.color", "blue");
        properties.setProperty("kaptcha.image.width", "140");
        properties.setProperty("kaptcha.image.height", "80");
        properties.setProperty("kaptcha.textproducer.font.size", "60");
        properties.setProperty("kaptcha.session.key", "code");
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);

        return defaultKaptcha;
    }

    /**
     * 配置hibernate的校验模式
     * 校验相关
     */
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure()
                // 配置快速失败返回模式：只要有一个验证失败，则返回
                .addProperty("hibernate.validator.fail_fast", "true").buildValidatorFactory();

        return validatorFactory.getValidator();
    }

    /**
     * 配置hibernate的校验模式
     * @return MethodValidationPostProcessor
     */
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
        // 设置validator模式为快速失败返回
        postProcessor.setValidator(validator());
        return postProcessor;
    }
}
